/*-----------------------------------------------------------------------------
	The contents of this file are subject to the Mozilla Public License
	Version 1.1 (the "License"); you may not use this file except in
	compliance with the License. You may obtain a copy of the License at
	http://www.mozilla.org/MPL/
	
	Software distributed under the License is distributed on an "AS IS"
	basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
	License for the specific language governing rights and limitations
	under the License.
	
	The Original Code is Fever Framework code.
	
	The Initial Developer of the Original Code is Romain Ecarnot.
	Portions created by Initial Developer are Copyright (C) 2006
	the Initial Developer. All Rights Reserved.
	
	Contributor(s):
	
	Unless required by applicable law or agreed to in writing, software
	distributed under the License is distributed on an "AS IS" BASIS,
	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
	See the License for the specific language governing permissions and
	limitations under the License.
-----------------------------------------------------------------------------*/

import fever.display.filters.FilterQuality;

import flash.filters.BevelFilter;
import flash.filters.BitmapFilter;
import flash.filters.BlurFilter;
import flash.filters.ColorMatrixFilter;
import flash.filters.DropShadowFilter;
import flash.filters.GlowFilter;
import flash.filters.GradientBevelFilter;
import flash.filters.GradientGlowFilter;

/**
 * Apply <strong>Flash filter</strong> on <strong>MovieClip</strong>.
 * 
 * <p>All methods starting with <strong>'set'</strong> ( ie {@link #setShadow} ) 
 * don't enqueue filter effects.<br />
 * If you call {@link #setShadow} twice, only one shadow filter is applied.
 * 
 * <p>If you want to enqueue filters, use methods starting with <strong>'add'</strong>
 * 
 * <p>Example
 * {@code
 *   var button : MovieClip = Fever.stage.createEmptyMovieClip( "name" );
 *   FilterBuilder.setShadow( button );
 * }
 * 
 * @author Romain Ecarnot
 */
class fever.display.FilterBuilder
{
	//-------------------------------------------------------------------------
	// Private properties
	//-------------------------------------------------------------------------
	
	private static var _lumTransform : ColorMatrixFilter = _initLuminanceTransform();
	 	
	
	//-------------------------------------------------------------------------
	// Public API
	//-------------------------------------------------------------------------
	
	/**
	 * Returns a default <strong>DropShadowFilter</strong>.
	 * 
	 * <ul>
	 *   <li>length : 0</li>
	 *   <li>direction : 45</li>
	 *   <li>alpha : 100</li>
	 *   <li>blurX : 10</li>
	 *   <li>blurY : 10</li>
	 *   <li>strength : 0.5</li>
	 *   <li>quality : {@link FilterQuality#HIGH}</li>
	 * </ul>
	 */
	public static function getSoftShadowFilter() : DropShadowFilter
	{
		return new DropShadowFilter( 0, 45, 0x000000, 100, 10, 10, 0.50, FilterQuality.HIGH );
	}
	
	/**
	 * Returns predefined greyscale color matrix. 
	 */
	public static function getToGrayFilter() : ColorMatrixFilter
	{
		return _lumTransform;
	}
	
	/**
	 * Sets a shadow filter.
	 * 
	 * @param filter ( optional ) DropShadowFilter filter
	 */
	public static function setShadow( target : MovieClip, filter : DropShadowFilter ) : DropShadowFilter
	{
		clearFilterType( target, DropShadowFilter );
		return addShadow( target, filter );
	}
	
	/**
	 * Adds a new shadow filter.
	 * 
	 * @param filter ( optional ) DropShadowFilter filter
	 */
	public static function addShadow( target : MovieClip, filter : DropShadowFilter ) : DropShadowFilter
	{
		if( !filter ) filter = new DropShadowFilter();
		addFilter( target, filter );
        return filter;
	}
	
	/**
	 * Removes all shadow filter from {@code target} MovieClip.
	 */
	public static function cleanShadow( target : MovieClip ) : Void
	{
		clearFilterType( target, DropShadowFilter );
	}
	
	/**
	 * Sets a glow filter.
	 * 
	 * @param filter ( optional ) GlowFilter filter
	 */
	public static function setGlow( target : MovieClip, filter : GlowFilter ) : GlowFilter
	{
		clearFilterType( target, GlowFilter );
		return addGlow( target, filter );
	}
	
	/**
	 * Sets a glow filter.
	 * 
	 * @param filter ( optional ) GlowFilter filter
	 */
	public static function addGlow( target : MovieClip, filter : GlowFilter ) : GlowFilter
	{
		if( !filter ) filter = new GlowFilter();
		addFilter( target, filter );
        return filter;
	}
	
	/**
	 * Removes all glow filter from passed-in {@code target} MovieClip.
	 */
	public static function cleanGlow( target : MovieClip ) : Void
	{
		clearFilterType( target, GlowFilter );
	}
	
	/**
	 * Sets a bevel filter.
	 * 
	 * @param filter ( optional ) BevelFilter filter
	 */
	public static function setBevel( target : MovieClip, filter : BevelFilter ) : BevelFilter
	{
		clearFilterType( target, BevelFilter );
		return addBevel( target, filter );
	}
	
	/**
	 * Adds a new bevel filter.
	 * 
	 * @param filter ( optional ) BevelFilter filter
	 */
	public static function addBevel( target : MovieClip, filter : BevelFilter ) : BevelFilter
	{
		if( !filter ) filter = new BevelFilter();
		addFilter( target, filter );
		return filter;
	}
	
	/**
	 * Removes all bevel filter from passed-in {@code target} MovieClip.
	 */
	public static function cleanBevel( target : MovieClip ) : Void
	{
		clearFilterType( target, BevelFilter );
	}
	
	/**
	 * Sets a color filter.
	 * 
	 * @param filter ColorMatrixFilter filter
	 */
	public static function setColorMatrix( target : MovieClip, filter : ColorMatrixFilter ) : ColorMatrixFilter
	{
		clearFilterType( target, ColorMatrixFilter );
		return addColorMatrix( target, filter );
	}
	
	/**
	 * Adds a new color filter.
	 * 
	 * @param filter ColorMatrixFilter filter
	 */
	public static function addColorMatrix( target : MovieClip, filter : ColorMatrixFilter ) : ColorMatrixFilter
	{
		if( !filter ) return null;
		addFilter( target, filter );
		return filter;
	}
	
	/**
	 * Sets a gradient glow filter.
	 * 
	 * @param filter GradientGlowFilter filter
	 */
	public static function setGradientGlow( target : MovieClip, filter : GradientGlowFilter ) : GradientGlowFilter
	{
		clearFilterType( target, GradientGlowFilter );
		return addGradientGlow( target, filter );
	}
	
	/**
	 * Adds a new gradient glow filter.
	 * 
	 * @param filter GradientGlowFilter filter
	 */
	public static function addGradientGlow( target : MovieClip, filter : GradientGlowFilter ) : GradientGlowFilter
	{
		if( !filter ) filter = new GradientGlowFilter();
		addFilter( target, filter );
		return filter;
	}
	
	/**
	 * Removes all gradient glow filter from passed-in {@code target} MovieClip.
	 */
	public static function cleanGradientGlow( target : MovieClip ) : Void
	{
		clearFilterType( target, GradientGlowFilter );
	}
	
	/**
	 * Sets a gradient bevel filter.
	 * 
	 * @param filter GradientGlowFilter filter
	 */
	public static function setGradientBevel( target : MovieClip, filter : GradientBevelFilter ) : GradientBevelFilter
	{
		clearFilterType( target, GradientBevelFilter );
		return addGradientBevel( target, filter );
	}
	
	/**
	 * Adds a new gradient bevel filter.
	 * 
	 * @param filter GradientBevelFilter filter
	 */
	public static function addGradientBevel( target : MovieClip, filter : GradientBevelFilter ) : GradientBevelFilter
	{
		if( !filter ) filter = new GradientBevelFilter();
		addFilter( target, filter );
        return filter;
	}
	
	/**
	 * Removes all gradient bevel filter from passed-in {@code target} MovieClip.
	 */
	public static function cleanGradientBevel( target : MovieClip ) : Void
	{
		clearFilterType( target, GradientBevelFilter );
	}
	
	/**
	 * Sets a blur filter.
	 * 
	 * @param filter ( optional ) BlurFilter filter
	 */
	public static function setBlur( target : MovieClip, filter : BlurFilter ) : BlurFilter
	{
		clearFilterType( target, BlurFilter );
		return addBlur( target, filter );
	}
	
	/**
	 * Adds a new blur filter.
	 * 
	 * @param filter ( optional ) BlurFilter filter
	 */
	public static function addBlur( target : MovieClip, filter : BlurFilter ) : BlurFilter
	{
		if( !filter ) filter = new BlurFilter();
		addFilter( target, filter );
        return filter;
	}
	
	/**
	 * Removes all blur filter from passed-in {@code target} MovieClip.
	 */
	public static function cleanBlur( target : MovieClip ) : Void
	{
		clearFilterType( target, BlurFilter );
	}
	
	/**
	 * Adds passed-in filter to passed-in {@code target} MovieClip.
	 * 
	 * @param filter BitmapFilter instance
	 */
	public static function addFilter( target : MovieClip, filter ) : Void
	{
		if( !target || !filter ) return;
		var tmp : Array = target.filters;
		tmp.push( filter );
		target.filters = tmp;
	}
	
	/**
	 * Removes passed-in filter from passed-in {@code target} MovieClip.
	 * 
	 * @param filter BitmapFilter instance
	 */
	public static function removeFilter( target : MovieClip, filter : BitmapFilter ) : Void
	{
		if( !target || !filter ) return;
		
        var tmp : Array = target.filters;
        var index : Number  = getFilterIndex( target, filter );
        if ( index > -1 )
        {
            tmp.splice( index, 1 );                
            target.filters = tmp;
        }
	}
	
	/**
	 * Removes all filters from passed-in {@code target} MovieClip.
	 */
	public static function clean( target : MovieClip ) : Void
	{
		target.filters = new Array();	
	}
	
	/**
	 * Removes all filter ( type as {@code filterType} parameter ) from 
	 * passed-in {@code target} MovieClip.
	 * 
	 * @param filterType Filter type
	 */
	public static function clearFilterType( target : MovieClip, filterType : Function ) : Void
	{
		if( !target || !filterType ) return;
		
		var len : Number = target.filters.length;
		var tmp : Array = new Array();
		
		for( var i : Number = 0; i < len; i++ )
		{
			var f : BitmapFilter = target.filters[i];
			if( !( f instanceof filterType ) ) tmp.push( f );
		}
		target.filters = tmp;
	}
	
	/**
	 * Returns filter index ( Filter Array position ).<br />
	 * The search is made on filter instance.
	 * 
	 * <p>Returns -1 if passed-in filter is not applied on 
	 * passed-in {@code target} MovieClip.
	 * 
	 * @param filterType Filter to search in passed-in 
	 * {@code target} MovieClip
	 */
	public static function getFilterIndex( target : MovieClip, filter : BitmapFilter ) : Number
	{
        if ( !target ) return -1;
        
        var pos : Number = target.filters.length;
        while( pos-- )
        {
            var f : BitmapFilter = target.filters[pos];
            if( f == filter )
            {
               return pos;
            }
        }
        return -1;
	}
	
	/**
	 * Returns filter index ( Filter Array position ).<br />
	 * The search is made on filter type.
	 * 
	 * <p>Returns -1 if passed-in filter type is not applied 
	 * on passed-in {@code target} MovieClip.
	 * 
	 * @param filterType Filter to search
	 */
	public static function getFilterTypeIndex( target : MovieClip, filterType : Function ) : Number
	{
        if ( !target ) return -1;
        
        var pos : Number = target.filters.length;
        while( pos-- )
        {
            var f : BitmapFilter = target.filters[pos];
            if( f instanceof filterType ) return pos;
        }
        return -1;
	}
	
	
	//-------------------------------------------------------------------------
	// Private implementation
	//-------------------------------------------------------------------------
	
	private static function _initLuminanceTransform() : ColorMatrixFilter
	{
		var rwgt : Number = .3086;
		var gwgt : Number = .6094;
		var bwgt : Number = .0820;
 
		var lumTransform : ColorMatrixFilter = new ColorMatrixFilter( 
			new Array (
				rwgt,   gwgt,   bwgt,   0.0,   0.0,
		        rwgt,   gwgt,   bwgt,   0.0,   0.0,
		        rwgt,   gwgt,   bwgt,   0.0,   0.0,
		        0.0,   	0.0,    0.0,   	1.0,   0.0
			)
		);
		return lumTransform;
	}
	
	/**
	 * Constructor..
	 */
	private function FilterBuilder() {}	
}